// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

// ************************************************************************* //
//  File: avtRemoveCellsFilter.C
// ************************************************************************* //

#include <avtRemoveCellsFilter.h>

#include <algorithm>

#include <vtkCellData.h>
#include <vtkCellLocator.h>
#include <vtkDataSet.h>
#include <vtkGenericCell.h>
#include <vtkPointData.h>
#include <vtkUnsignedIntArray.h>
#include <vtkUnstructuredGrid.h>
#include <vtkVisItUtility.h>

using namespace std;

// ****************************************************************************
//  Method: avtRemoveCellsFilter constructor
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
// ****************************************************************************

avtRemoveCellsFilter::avtRemoveCellsFilter()
{
}


// ****************************************************************************
//  Method: avtRemoveCellsFilter destructor
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
//  Modifications:
//
// ****************************************************************************

avtRemoveCellsFilter::~avtRemoveCellsFilter()
{
}


// ****************************************************************************
//  Method:  avtRemoveCellsFilter::Create
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
// ****************************************************************************

avtFilter *
avtRemoveCellsFilter::Create()
{
    return new avtRemoveCellsFilter();
}


// ****************************************************************************
//  Method:      avtRemoveCellsFilter::SetAtts
//
//  Purpose:
//      Sets the state of the filter based on the attribute object.
//
//  Arguments:
//      a        The attributes to use.
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
// ****************************************************************************

void
avtRemoveCellsFilter::SetAtts(const AttributeGroup *a)
{
    atts = *(const RemoveCellsAttributes*)a;
}


// ****************************************************************************
//  Method: avtRemoveCellsFilter::Equivalent
//
//  Purpose:
//      Returns true if creating a new avtRemoveCellsFilter with the given
//      parameters would result in an equivalent avtRemoveCellsFilter.
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
// ****************************************************************************

bool
avtRemoveCellsFilter::Equivalent(const AttributeGroup *a)
{
    return (atts == *(RemoveCellsAttributes*)a);
}


// ****************************************************************************
//  Method: avtRemoveCellsFilter::ExecuteData
//
//  Purpose:
//      Sends the specified input and output through the RemoveCells filter.
//
//  Arguments:
//      in_dr      The input data representation.
//
//  Returns:       The output data representation.
//
//  Programmer: haddox1 -- generated by xml2info
//  Creation:   Mon Jun 2 13:48:29 PST 2003
//
//  Modifications:
//
//    Hank Childs, Thu Mar 10 09:55:08 PST 2005
//    Fix memory leak.
//
//    Eric Brugger, Thu Jul 31 19:27:52 PDT 2014
//    Modified the class to work with avtDataRepresentation.
//
// ****************************************************************************

avtDataRepresentation *
avtRemoveCellsFilter::ExecuteData(avtDataRepresentation *in_dr)
{
    //
    // Get the VTK data set and the domain number.
    //
    vtkDataSet *in_ds = in_dr->GetDataVTK();
    int domain = in_dr->GetDomain();

    vector<int> cells;
    ParseAtts(domain, cells);

    if(cells.size() == 0)
    {
        return in_dr;
    }

    sort(cells.begin(), cells.end());
  
    vtkCellData *inCD = in_ds->GetCellData();
    
    vtkUnstructuredGrid *ug = vtkUnstructuredGrid::New();
    vtkCellData *outCD = ug->GetCellData();
    vtkPoints *pts = vtkVisItUtility::GetPoints(in_ds);
    ug->SetPoints(pts);
    pts->Delete();
    ug->GetPointData()->PassData(in_ds->GetPointData());
    
    int nCells = in_ds->GetNumberOfCells();
    
    ug->Allocate(nCells);
    outCD->CopyAllocate(inCD);

    vtkUnsignedIntArray *origCellArr = 
                (vtkUnsignedIntArray *)inCD->GetArray("avtOriginalCellNumbers");
    unsigned int * origCellNums = NULL;
    if (origCellArr)
        origCellNums = origCellArr->GetPointer(0); 
   
    int i;
    int cIndex = 0;
    vtkGenericCell *cell = vtkGenericCell::New();
    for (i = 0; i < nCells; ++i)
    {
        //
        // If the cell is the next on our list to remove, increment, and skip
        //
        if (origCellNums)
        {
            if (cells[cIndex] == (int)origCellNums[1 + 2 * i])
            {
                ++cIndex;
                continue;
            }
        }
        else if (cells[cIndex] == i)
        {
            ++cIndex;
            continue;
        }
        
        in_ds->GetCell(i, cell);    
        int newId = ug->InsertNextCell(cell->GetCellType(), 
                                       cell->GetPointIds());
        outCD->CopyData(inCD, i, newId);
    }
    cell->Delete();

    outCD->Squeeze();
   
    avtDataRepresentation *out_dr = new avtDataRepresentation(ug,
        in_dr->GetDomain(), in_dr->GetLabel());

    ug->Delete();

    return out_dr;
}

// ****************************************************************************
//  Method: avtRemoveCellsFilter::ParseAtts
//
//  Purpose:
//      Parse the information in the attributes, and get out a list of
//      cells for a specified domain.
//
//  Arguments:
//      domain      The domain to look in.
//      cells       The vector to fill with cell ids.
//
//  Programmer: Akira Haddox
//  Creation:   June 2, 2003
//
// ****************************************************************************

void
avtRemoveCellsFilter::ParseAtts(int domain, vector<int> &cells)
{
    const vector<int> &cV = atts.GetCellList();
    const vector<int> &dV = atts.GetDomainList();
    
    for (size_t i = 0; i < cV.size(); ++i)
    {
        if (dV[i] == domain)
            cells.push_back(cV[i]);
    }
}


// ****************************************************************************
//  Method: avtRemoveCellsFilter::UpdateDataObjectInfo
//
//  Purpose:
//      Indicates the zones no longer correspond to the original problem.
//
//  Programmer: Akira Haddox
//  Creation:   June 2, 2003
//
//  Modifications:
//    Brad Whitlock, Mon Apr  7 15:55:02 PDT 2014
//    Add filter metadata used in export.
//    Work partially supported by DOE Grant SC0007548.
//
// ****************************************************************************

void
avtRemoveCellsFilter::UpdateDataObjectInfo(void)
{
    GetOutput()->GetInfo().GetValidity().InvalidateZones();
    GetOutput()->GetInfo().GetAttributes().AddFilterMetaData("RemoveCells");
}
